{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": [],
      "include_colab_link": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/nceder/qpb4e/blob/main/code/Chapter%2014/Chapter_14.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "# 14 Exceptions"
      ],
      "metadata": {
        "id": "OtEGRlOpyNPc"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Python built-in exceptions\n",
        "\n",
        "```python\n",
        "BaseException\n",
        "    BaseExceptionGroup\n",
        "    GeneratorExit\n",
        "    KeyboardInterrupt\n",
        "    SystemExit\n",
        "    Exception\n",
        "        ArithmeticError\n",
        "            FloatingPointError\n",
        "            OverflowError\n",
        "            ZeroDivisionError\n",
        "        AssertionError\n",
        "        AttributeError\n",
        "        BufferError\n",
        "        EOFError\n",
        "        ExceptionGroup [BaseExceptionGroup]\n",
        "        ImportError\n",
        "            ModuleNotFoundError\n",
        "        LookupError\n",
        "            IndexError\n",
        "            KeyError\n",
        "        MemoryError\n",
        "        NameError\n",
        "            UnboundLocalError\n",
        "        OSError\n",
        "            BlockingIOError\n",
        "            ChildProcessError\n",
        "            ConnectionError\n",
        "                BrokenPipeError\n",
        "                ConnectionAbortedError\n",
        "                ConnectionRefusedError\n",
        "                ConnectionResetError\n",
        "            FileExistsError\n",
        "            FileNotFoundError\n",
        "            InterruptedError\n",
        "            IsADirectoryError\n",
        "            NotADirectoryError\n",
        "            PermissionError\n",
        "            ProcessLookupError\n",
        "            TimeoutError\n",
        "        ReferenceError\n",
        "        RuntimeError\n",
        "            NotImplementedError\n",
        "            PythonFinalizationError\n",
        "            RecursionError\n",
        "        StopAsyncIteration\n",
        "        StopIteration\n",
        "        SyntaxError\n",
        "            IncompleteInputError\n",
        "            IndentationError\n",
        "                TabError\n",
        "        SystemError\n",
        "        TypeError\n",
        "        ValueError\n",
        "            UnicodeError\n",
        "                UnicodeDecodeError\n",
        "                UnicodeEncodeError\n",
        "                UnicodeTranslateError\n",
        "        Warning\n",
        "            BytesWarning\n",
        "            DeprecationWarning\n",
        "            EncodingWarning\n",
        "            FutureWarning\n",
        "            ImportWarning\n",
        "            PendingDeprecationWarning\n",
        "            ResourceWarning\n",
        "            RuntimeWarning\n",
        "            SyntaxWarning\n",
        "            UnicodeWarning\n",
        "            UserWarning\n",
        "```"
      ],
      "metadata": {
        "id": "34HldUlryX3L"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "## 14.2.2 Raising exceptions"
      ],
      "metadata": {
        "id": "Ciy2_KQqyR0D"
      }
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "lSPNjdSrfF6W",
        "outputId": "4c7db0e9-ba91-4dea-9149-d6a37e6794b8",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 159
        }
      },
      "source": [
        "alist = [1, 2, 3]\n",
        "element = alist[7]"
      ],
      "execution_count": 1,
      "outputs": [
        {
          "output_type": "error",
          "ename": "IndexError",
          "evalue": "list index out of range",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mIndexError\u001b[0m                                Traceback (most recent call last)",
            "\u001b[0;32m<ipython-input-1-189983935c4d>\u001b[0m in \u001b[0;36m<cell line: 2>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0malist\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m3\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0melement\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0malist\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m7\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
            "\u001b[0;31mIndexError\u001b[0m: list index out of range"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Rfu17Q3EfF6Y"
      },
      "source": [
        "raise IndexError(\"Just kidding\")"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Try This: Catching exceptions\n",
        "\n",
        "Write code that gets two numbers from the user and divides the first number by the second. Check for and catch the exception that occurs if the second number is zero (`ZeroDivisionError`).\n",
        "\n",
        "The code of your program should do the following:\n",
        "```\n",
        "Please enter an integer: 1\n",
        "Please enter another integer: 0\n",
        "Can't divide by zero.\n",
        "```"
      ],
      "metadata": {
        "id": "eEa_4myByynz"
      }
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "0WfboNejzfku"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# @title\n",
        "x = int(input(\"Please enter an integer: \"))\n",
        "y = int(input(\"Please enter another integer: \"))\n",
        "\n",
        "try:\n",
        "    z = x / y\n",
        "    print(z)\n",
        "except ZeroDivisionError as e:\n",
        "    print(\"Can't divide by zero.\")"
      ],
      "metadata": {
        "cellView": "form",
        "id": "ZDq42Tw-JQnR"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "## 14.2.4 Defining new exceptions"
      ],
      "metadata": {
        "id": "Yhcz0KBnziO6"
      }
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "9wAuhqTmfF6Y"
      },
      "source": [
        "class MyError(Exception):\n",
        "    pass"
      ],
      "execution_count": 2,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "oqSNcJjFfF6Y",
        "outputId": "1e71b32e-0db8-4d3d-efbe-bd752cc30ced",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 141
        }
      },
      "source": [
        "raise MyError(\"Some information about what went wrong\")"
      ],
      "execution_count": 3,
      "outputs": [
        {
          "output_type": "error",
          "ename": "MyError",
          "evalue": "Some information about what went wrong",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mMyError\u001b[0m                                   Traceback (most recent call last)",
            "\u001b[0;32m<ipython-input-3-04991f64f605>\u001b[0m in \u001b[0;36m<cell line: 1>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mMyError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Some information about what went wrong\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
            "\u001b[0;31mMyError\u001b[0m: Some information about what went wrong"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "hzKfVqDmfF6Y",
        "outputId": "a06e2c40-4542-4536-ba5a-49864e6104e0",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "try:\n",
        "    raise MyError(\"Some information about what went wrong\")\n",
        "except MyError as error:\n",
        "    print(\"Situation:\", error)"
      ],
      "execution_count": 4,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Situation: Some information about what went wrong\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "P75sYqYFfF6Z",
        "outputId": "dee8c1ca-d256-4504-d7df-cf8486b1e564",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "try:\n",
        "    raise MyError(\"Some information\", \"my_filename\", 3)\n",
        "except MyError as error:\n",
        "    print(\"Situation: {0} with file {1}\\n error code: {2}\".format(\n",
        "        error.args[0],\n",
        " error.args[1], error.args[2]))"
      ],
      "execution_count": 5,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Situation: Some information with file my_filename\n",
            " error code: 3\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## 14.2.5 Exception groups\n"
      ],
      "metadata": {
        "id": "oGK9Mhk4Kne7"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "import sys\n",
        "if sys.version_info.minor < 11:\n",
        "  raise RuntimeError(f\"Python version must be >= 3.11 to use exception groups, current version is {sys.version}\")\n"
      ],
      "metadata": {
        "id": "0rJa0lLVLJCq",
        "outputId": "336e66cd-103b-4f36-d2c5-b8e30771d7df",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 176
        }
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "error",
          "ename": "RuntimeError",
          "evalue": "Python version must be >= 3.11 to use exception groups, current version is 3.10.12 (main, Mar 22 2024, 16:50:05) [GCC 11.4.0]",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mRuntimeError\u001b[0m                              Traceback (most recent call last)",
            "\u001b[0;32m<ipython-input-4-d4348c517e18>\u001b[0m in \u001b[0;36m<cell line: 2>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0msys\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      2\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0msys\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mversion_info\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mminor\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m11\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m   \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"Python version must be >= 3.11 to use exception groups, current version is {sys.version}\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
            "\u001b[0;31mRuntimeError\u001b[0m: Python version must be >= 3.11 to use exception groups, current version is 3.10.12 (main, Mar 22 2024, 16:50:05) [GCC 11.4.0]"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "**This will not run (will raise a SyntaxError) on Python versions before. 3.11**"
      ],
      "metadata": {
        "id": "i8We4o6ZWo_K"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "try:\n",
        "    raise ExceptionGroup(\"Multiple exceptions\",[TypeError(),  #A\n",
        "                          FileNotFoundError(), ValueError()])\n",
        "except* TypeError:    #B\n",
        "    message += f\"Handling TypeError\\n\"\n",
        "except* IOError: #C\n",
        "    message += f\"Handling IOError\\n\"\n",
        "except* ValueError:   #D\n",
        "    message += f\"Handling ValueError\\n\"\n",
        "finally:\n",
        "    print(message)\n"
      ],
      "metadata": {
        "id": "-C0_UCt_Wgsg"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "## 14.2.6 Debugging programs with the assert statement"
      ],
      "metadata": {
        "id": "KgixTYoFzulS"
      }
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "0PEOMi-6fF6Z",
        "outputId": "77af6b2a-7ae7-4a77-adb0-d06b315ecd59",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 159
        }
      },
      "source": [
        "x = (1, 2, 3)\n",
        "assert len(x) > 5, \"len(x) not > 5\""
      ],
      "execution_count": 6,
      "outputs": [
        {
          "output_type": "error",
          "ename": "AssertionError",
          "evalue": "len(x) not > 5",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mAssertionError\u001b[0m                            Traceback (most recent call last)",
            "\u001b[0;32m<ipython-input-6-52a42f33655e>\u001b[0m in \u001b[0;36m<cell line: 2>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"len(x) not > 5\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
            "\u001b[0;31mAssertionError\u001b[0m: len(x) not > 5"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Try This: The assert statement\n",
        "\n",
        "Write a simple program that gets a number from the user and then uses the assert statement to raise an exception if the number is zero. Test to make sure that the assert statement fires; then turn it off, using one of the methods mentioned in this section.\n",
        "\n"
      ],
      "metadata": {
        "id": "nRyX_Du_z4IH"
      }
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "IFxBP8Gyz94z"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# @title\n",
        "x = int(input(\"Please enter a non-zero integer: \"))\n",
        "\n",
        "assert x != 0, \"Integer can not be zero.\"\n"
      ],
      "metadata": {
        "cellView": "form",
        "id": "Y-sFA7poK3jm"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "## 14.2.9 Example: exceptions in normal evaluation"
      ],
      "metadata": {
        "id": "7xa9Sxmm0FoF"
      }
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "4x7_sO7zfF6Z"
      },
      "source": [
        "def cell_value(string):\n",
        "    try:\n",
        "        return float(string)\n",
        "    except ValueError:\n",
        "        if string == \"\":\n",
        "            return 0\n",
        "        else:\n",
        "            return None"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "9Gg6rs6ifF6Z"
      },
      "source": [
        "def safe_apply(function, x, y, spreadsheet):\n",
        "    try:\n",
        "        return function(x, y, spreadsheet)\n",
        "    except TypeError:\n",
        "        return None"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Try This: Exceptions\n",
        "What code would you use to create a custom `ValueTooLarge` exception and raise that exception if the variable `x` is over 1000?"
      ],
      "metadata": {
        "id": "eGrfd0wK0MJ0"
      }
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "N7LO9lP70cIS"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# @title\n",
        "class ValueTooLarge(Exception):\n",
        "    pass\n",
        "\n",
        "x = 1001\n",
        "if x > 1000:\n",
        "    raise ValueTooLarge()"
      ],
      "metadata": {
        "cellView": "form",
        "id": "7TFLDY21LG0F"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "# 14.3 Context managers using the `with` keyword"
      ],
      "metadata": {
        "id": "XHS8McSv0eGn"
      }
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "buE8HONlfF6a"
      },
      "source": [
        "! touch empty.txt\n",
        "filename = \"empty.txt\"\n",
        "try:\n",
        "    infile = open(filename)\n",
        "    data = infile.read()\n",
        "finally:\n",
        "    infile.close()"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "GZJJSjrTfF6a"
      },
      "source": [
        "with open(filename) as infile:\n",
        "    data = infile.read()"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "with open(\"empty.txt\") as infile, open(\"other.txt\", \"w\") as outfile:\n",
        "    data = infile.read()\n",
        "    outfile.write(data)"
      ],
      "metadata": {
        "id": "yUardW8qXjlN"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "with (\n",
        "    open(\"empty.txt\") as infile,\n",
        "    open(\"other.txt\", \"w\") as outfile\n",
        "):\n",
        "    data = infile.read()\n",
        "    outfile.write(data)"
      ],
      "metadata": {
        "id": "1dYoW16hX4-g"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "# 14.4 Custom exceptions\n",
        "\n",
        "Think about the module you wrote in chapter 9 to count word frequencies. What errors might reasonably occur in those functions? Refactor those functions to handle those exception conditions appropriately."
      ],
      "metadata": {
        "id": "bTeo9gJn0tG4"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Author's solution"
      ],
      "metadata": {
        "id": "4JjA1RNFazHg"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "!wget https://raw.githubusercontent.com/nceder/qpb4e/main/code/Chapter%2006/moby_01.txt &> /dev/null  && echo Downloaded"
      ],
      "metadata": {
        "id": "5YtXs7MKDCee",
        "outputId": "1b0c40c2-f7b8-4c16-9041-28bd741912f4",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Downloaded\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Author's version\n",
        "import string\n",
        "punct = str.maketrans('', '', string.punctuation)\n",
        "\n",
        "class EmptyStringError(Exception):\n",
        "    pass\n",
        "def clean_line(line):\n",
        "    \"\"\"changes case and removes punctuation\"\"\"\n",
        "\n",
        "    # raise exception if line is empty\n",
        "    # Comment out/remove two lines below to ignore EmptyStringError condition\n",
        "    if not line.strip():\n",
        "        raise EmptyStringError()\n",
        "    # make all one case\n",
        "    cleaned_line = line.lower()\n",
        "\n",
        "    # remove punctuation\n",
        "    cleaned_line = cleaned_line.translate(punct)\n",
        "    return cleaned_line\n",
        "\n",
        "\n",
        "def count_words(words):\n",
        "    \"\"\"takes list of cleaned words, returns count dictionary\"\"\"\n",
        "    word_count = {}\n",
        "    for word in words:\n",
        "        try:\n",
        "            count = word_count.setdefault(word, 0)\n",
        "        except TypeError:\n",
        "            #if 'word' is not hashable, skip to next word.\n",
        "            pass\n",
        "        word_count[word] += 1\n",
        "    return word_count\n",
        "\n",
        "def word_stats(word_count):\n",
        "    \"\"\"Takes word count dictionary and returns top, bottom five entries\"\"\"\n",
        "    word_list = list(word_count.items())\n",
        "    try:\n",
        "        word_list.sort(key=lambda x: x[1])\n",
        "    except TypeError as e:\n",
        "        print(f\"Error sorting word list: {e}\")\n",
        "\n",
        "    least_common = word_list[:5]\n",
        "    most_common = word_list[-1:-6:-1]\n",
        "\n",
        "    return most_common, least_common\n",
        "\n",
        "def get_words(line):\n",
        "    \"\"\"splits line into words, and rejoins with newlines\"\"\"\n",
        "    words = line.split()\n",
        "    return \"\\n\".join(words) + \"\\n\"\n",
        "\n",
        "def clean_file(filename, outfilename):\n",
        "    try:\n",
        "        with open(filename) as infile, open(outfilename, \"w\") as outfile:\n",
        "            for line in infile:\n",
        "                if line.strip():\n",
        "                    cleaned_line = clean_line(line)\n",
        "\n",
        "                    cleaned_words = get_words(cleaned_line)\n",
        "\n",
        "                    # write all words for line\n",
        "                    outfile.write(cleaned_words)\n",
        "    except IOError as e:\n",
        "        print(f\"Error reading or writing to file: {e}\")\n",
        "\n",
        "def load_words(cleaned_filename):\n",
        "    words = []\n",
        "    print(cleaned_filename)\n",
        "    try:\n",
        "        with open(cleaned_filename) as infile:\n",
        "            for word in infile:\n",
        "                if word.strip():\n",
        "                    words.append(word.strip())\n",
        "    except IOError as e:\n",
        "        print(f\"Error reading or writing to file: {e}\")\n",
        "    return words\n",
        "\n",
        "clean_file(\"moby_01.txt\", \"moby_clean.txt\")\n",
        "moby_words = load_words(\"moby_clean.txt\")\n",
        "word_count = count_words(moby_words)\n",
        "\n",
        "most, least = word_stats(word_count)\n",
        "print(\"Most common words:\")\n",
        "for word in most:\n",
        "    print(word)\n",
        "print(\"\\nLeast common words:\")\n",
        "for word in least:\n",
        "    print(word)"
      ],
      "metadata": {
        "id": "_bCs7hlE3-Mv",
        "outputId": "cc96e4c6-61c3-4931-c76c-cc751dfd69c3",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "moby_clean.txt\n",
            "Most common words:\n",
            "('the', 14)\n",
            "('i', 9)\n",
            "('and', 9)\n",
            "('of', 8)\n",
            "('is', 7)\n",
            "\n",
            "Least common words:\n",
            "('call', 1)\n",
            "('ishmael', 1)\n",
            "('years', 1)\n",
            "('ago', 1)\n",
            "('never', 1)\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Original Copilot code"
      ],
      "metadata": {
        "id": "lX9ZK6E3gdLi"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# Generated by Copilot\n",
        "import string\n",
        "\n",
        "def clean_line(line):\n",
        "    # Convert the line to lowercase\n",
        "    line = line.lower()\n",
        "\n",
        "    # Remove punctuation from the line\n",
        "    line = line.translate(str.maketrans('', '', string.punctuation))\n",
        "\n",
        "    return line\n",
        "\n",
        "def write_words_to_file(words, output_file):\n",
        "    # Write each word to the output file\n",
        "    for word in words:\n",
        "        output_file.write(word + '\\n')\n",
        "\n",
        "def count_word_occurrences(words):\n",
        "    # Count the occurrences of each word using a dictionary\n",
        "    word_counts = {}\n",
        "    for word in words:\n",
        "        if word in word_counts:\n",
        "            word_counts[word] += 1\n",
        "        else:\n",
        "            word_counts[word] = 1\n",
        "\n",
        "    return word_counts\n",
        "\n",
        "def print_common_words(word_counts, n):\n",
        "    # Sort the word counts in descending order\n",
        "    sorted_word_counts = sorted(word_counts.items(), key=lambda x: x[1], reverse=True)\n",
        "\n",
        "    # Print the n most common words and their occurrences\n",
        "    print(f\"{n} most common words:\")\n",
        "    for word, count in sorted_word_counts[:n]:\n",
        "        print(f\"{word}: {count}\")\n",
        "\n",
        "def print_least_common_words(word_counts, n):\n",
        "    # Sort the word counts in descending order\n",
        "    sorted_word_counts = sorted(word_counts.items(), key=lambda x: x[1], reverse=True)\n",
        "\n",
        "    # Print the n least common words and their occurrences\n",
        "    print(f\"{n} least common words:\")\n",
        "    for word, count in sorted_word_counts[-n:]:\n",
        "        print(f\"{word}: {count}\")\n",
        "\n",
        "def process_file(input_file_path, output_file_path):\n",
        "    # Open the input file for reading\n",
        "    with open(input_file_path, 'r') as input_file:\n",
        "        # Open the output file for writing\n",
        "        with open(output_file_path, 'w') as output_file:\n",
        "            # Iterate over each line in the input file\n",
        "            for line in input_file:\n",
        "                # Clean the line\n",
        "                cleaned_line = clean_line(line)\n",
        "\n",
        "                # Split the line into words\n",
        "                words = cleaned_line.split()\n",
        "\n",
        "                # Write the words to the output file\n",
        "                write_words_to_file(words, output_file)\n",
        "\n",
        "def main():\n",
        "    input_file_path = 'moby_01.txt'\n",
        "    output_file_path = 'moby_01_clean.txt'\n",
        "\n",
        "    # Process the file\n",
        "    process_file(input_file_path, output_file_path)\n",
        "\n",
        "    # Open the file\n",
        "    with open(output_file_path, 'r') as file:\n",
        "        # Read the file content\n",
        "        content = file.read()\n",
        "\n",
        "    # Split the content into words\n",
        "    words = content.split()\n",
        "\n",
        "    # Count word occurrences\n",
        "    word_counts = count_word_occurrences(words)\n",
        "\n",
        "    # Print the five most common words and their occurrences\n",
        "    print_common_words(word_counts, 5)\n",
        "\n",
        "    # Print the five least common words and their occurrences\n",
        "    print_least_common_words(word_counts, 5)\n",
        "\n",
        "if __name__ == \"__main__\":\n",
        "    main()"
      ],
      "metadata": {
        "id": "op6WViWIgYAH"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "### New refactored code from Copilot"
      ],
      "metadata": {
        "id": "PPmcjy63iDUD"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# Generated by Copilot\n",
        "import string\n",
        "def clean_line(line):\n",
        "    # Convert the line to lowercase\n",
        "    line = line.lower()\n",
        "\n",
        "    # Remove punctuation from the line\n",
        "    line = line.translate(str.maketrans('', '', string.punctuation))\n",
        "\n",
        "    return line\n",
        "\n",
        "#=== Refactored code to add exception handling===========\n",
        "def write_words_to_file(words, output_file):\n",
        "    try:\n",
        "        for word in words:\n",
        "            output_file.write(word + '\\n')\n",
        "    except IOError as e:\n",
        "        print(f\"Error writing to file: {e}\")\n",
        "\n",
        "def count_word_occurrences(words):\n",
        "    if not hasattr(words, '__iter__'):\n",
        "        raise TypeError(\"Input must be iterable\")\n",
        "\n",
        "    word_counts = {}\n",
        "    for word in words:\n",
        "        if word in word_counts:\n",
        "            word_counts[word] += 1\n",
        "        else:\n",
        "            word_counts[word] = 1\n",
        "\n",
        "    return word_counts\n",
        "\n",
        "def print_common_words(word_counts, n):\n",
        "    if not isinstance(n, int) or n <= 0:\n",
        "        raise ValueError(\"n must be a positive integer\")\n",
        "\n",
        "    sorted_word_counts = sorted(word_counts.items(), key=lambda x: x[1], reverse=True)\n",
        "\n",
        "    print(f\"{n} most common words:\")\n",
        "    try:\n",
        "        for word, count in sorted_word_counts[:n]:\n",
        "            print(f\"{word}: {count}\")\n",
        "    except IndexError as e:\n",
        "        print(f\"Less than {n} words in input: {e}\")\n",
        "\n",
        "def print_least_common_words(word_counts, n):\n",
        "    if not isinstance(n, int) or n <= 0:\n",
        "        raise ValueError(\"n must be a positive integer\")\n",
        "\n",
        "    sorted_word_counts = sorted(word_counts.items(), key=lambda x: x[1])\n",
        "\n",
        "    print(f\"{n} least common words:\")\n",
        "    try:\n",
        "        for word, count in sorted_word_counts[:n]:\n",
        "            print(f\"{word}: {count}\")\n",
        "    except IndexError as e:\n",
        "        print(f\"Less than {n} words in input: {e}\")\n",
        "\n",
        "#=== End of refactored code to add exception handling===========\n",
        "\n",
        "def process_file(input_file_path, output_file_path):\n",
        "    # Open the input file for reading\n",
        "    with open(input_file_path, 'r') as input_file:\n",
        "        # Open the output file for writing\n",
        "        with open(output_file_path, 'w') as output_file:\n",
        "            # Iterate over each line in the input file\n",
        "            for line in input_file:\n",
        "                # Clean the line\n",
        "                cleaned_line = clean_line(line)\n",
        "\n",
        "                # Split the line into words\n",
        "                words = cleaned_line.split()\n",
        "\n",
        "                # Write the words to the output file\n",
        "                write_words_to_file(words, output_file)\n",
        "\n",
        "def main():\n",
        "    input_file_path = 'moby_01.txt'\n",
        "    output_file_path = 'moby_01_clean.txt'\n",
        "\n",
        "    # Process the file\n",
        "    process_file(input_file_path, output_file_path)\n",
        "\n",
        "    # Open the file\n",
        "    with open(output_file_path, 'r') as file:\n",
        "        # Read the file content\n",
        "        content = file.read()\n",
        "\n",
        "    # Split the content into words\n",
        "    words = content.split()\n",
        "\n",
        "    # Count word occurrences\n",
        "    word_counts = count_word_occurrences(words)\n",
        "\n",
        "    # Print the five most common words and their occurrences\n",
        "    print_common_words(word_counts, 5)\n",
        "\n",
        "    # Print the five least common words and their occurrences\n",
        "    print_least_common_words(word_counts, 5)\n",
        "\n",
        "if __name__ == \"__main__\":\n",
        "    main()"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "pM1DAFnjghHl",
        "outputId": "c2967f78-5f68-4910-c57e-ee5a50aafaa6"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "5 most common words:\n",
            "the: 14\n",
            "and: 9\n",
            "i: 9\n",
            "of: 8\n",
            "is: 7\n",
            "5 least common words:\n",
            "call: 1\n",
            "ishmael: 1\n",
            "years: 1\n",
            "ago: 1\n",
            "never: 1\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Original Colaboratory code"
      ],
      "metadata": {
        "id": "eR78shF7qs3E"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# Generated by Colaboratory\n",
        "# prompt: Refactor the code in the previous 2 cells into functions for cleaning\n",
        "#         and processing the data.  The goal should be that most of the logic is\n",
        "#         moved into functions.\n",
        "\n",
        "# Function to clean a line of text by converting it to lowercase and removing punctuation\n",
        "def clean_line(line):\n",
        "  line = line.lower()\n",
        "  line = line.translate(str.maketrans('', '', string.punctuation))\n",
        "  return line\n",
        "\n",
        "# Function to split a line of text into words and write each word to a new line in a file\n",
        "def write_words_to_file(line, output_file):\n",
        "  words = line.split()\n",
        "  for word in words:\n",
        "    output_file.write(word + '\\n')\n",
        "\n",
        "# Function to count the occurrences of each word in a list of words\n",
        "def count_word_occurrences(words):\n",
        "  word_counts = {}\n",
        "  for word in words:\n",
        "    if word not in word_counts:\n",
        "      word_counts[word] = 0\n",
        "    word_counts[word] += 1\n",
        "  return word_counts\n",
        "\n",
        "# Function to find the most and least common words in a dictionary of word counts\n",
        "def find_most_and_least_common_words(word_counts):\n",
        "  most_common = sorted(word_counts.items(), key=lambda item: item[1], reverse=True)[:5]\n",
        "  least_common = sorted(word_counts.items(), key=lambda item: item[1])[:5]\n",
        "  return most_common, least_common\n",
        "\n",
        "# Open the input file for reading\n",
        "with open('moby_01.txt', 'r') as input_file:\n",
        "  # Open the output file for writing\n",
        "  with open('moby_01_clean.txt', 'w') as output_file:\n",
        "    # Iterate over each line in the input file\n",
        "    for line in input_file:\n",
        "      # Clean the line of text\n",
        "      cleaned_line = clean_line(line)\n",
        "\n",
        "      # Write each word in the clean line to the output file\n",
        "      write_words_to_file(cleaned_line, output_file)\n",
        "\n",
        "# Open the file and read the text into a variable.\n",
        "with open('moby_01_clean.txt', 'r') as f:\n",
        "  text = f.read()\n",
        "\n",
        "# Split the text into words.\n",
        "words = text.split()\n",
        "\n",
        "# Count the occurrences of each word.\n",
        "word_counts = count_word_occurrences(words)\n",
        "\n",
        "# Find the most and least common words.\n",
        "most_common, least_common = find_most_and_least_common_words(word_counts)\n",
        "\n",
        "# Print the results.\n",
        "print(\"Most common words:\")\n",
        "for word, count in most_common:\n",
        "  print(f\"{word}: {count}\")\n",
        "\n",
        "print(\"\\nLeast common words:\")\n",
        "for word, count in least_common:\n",
        "  print(f\"{word}: {count}\")\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "D9bUxDaYdypW",
        "outputId": "5872fd99-5ed5-4484-836a-bef65852d766"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Most common words:\n",
            "the: 14\n",
            "and: 9\n",
            "i: 9\n",
            "of: 8\n",
            "is: 7\n",
            "\n",
            "Least common words:\n",
            "call: 1\n",
            "ishmael: 1\n",
            "years: 1\n",
            "ago: 1\n",
            "never: 1\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Colaboratory reactored code with exception handling\n"
      ],
      "metadata": {
        "id": "Xj402qbiq7lE"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# prompt: Refactor the code in the cell above to handle errors that might\n",
        "#         reasonably occur in those functions appropriately.\n",
        "import string\n",
        "# Function to clean a line of text by converting it to lowercase\n",
        "# and removing punctuation\n",
        "def clean_line(line):\n",
        "  try:\n",
        "    line = line.lower()\n",
        "    line = line.translate(str.maketrans('', '', string.punctuation))\n",
        "  except Exception as e:\n",
        "    raise Exception(\"Error cleaning line: {}\".format(e))\n",
        "  return line\n",
        "\n",
        "# Function to split a line of text into words and write each word to a new line in a file\n",
        "def write_words_to_file(line, output_file):\n",
        "  try:\n",
        "    words = line.split()\n",
        "    for word in words:\n",
        "      output_file.write(word + '\\n')\n",
        "  except Exception as e:\n",
        "    raise Exception(\"Error writing words to file: {}\".format(e))\n",
        "\n",
        "# Function to count the occurrences of each word in a list of words\n",
        "def count_word_occurrences(words):\n",
        "  word_counts = {}\n",
        "  for word in words:\n",
        "    try:\n",
        "      if word not in word_counts:\n",
        "        word_counts[word] = 0\n",
        "      word_counts[word] += 1\n",
        "    except Exception as e:\n",
        "      raise Exception(\"Error counting word occurrences: {}\".format(e))\n",
        "  return word_counts\n",
        "\n",
        "# Function to find the most and least common words in a dictionary of word counts\n",
        "def find_most_and_least_common_words(word_counts):\n",
        "  try:\n",
        "    most_common = sorted(word_counts.items(), key=lambda item: item[1], reverse=True)[:5]\n",
        "    least_common = sorted(word_counts.items(), key=lambda item: item[1])[:5]\n",
        "  except Exception as e:\n",
        "    raise Exception(\"Error finding most and least common words: {}\".format(e))\n",
        "  return most_common, least_common\n",
        "\n",
        "# Open the input file for reading\n",
        "with open('moby_01.txt', 'r') as input_file:\n",
        "  # Open the output file for writing\n",
        "  with open('moby_01_clean.txt', 'w') as output_file:\n",
        "    # Iterate over each line in the input file\n",
        "    for line in input_file:\n",
        "      # Clean the line of text\n",
        "      try:\n",
        "        cleaned_line = clean_line(line)\n",
        "      except Exception as e:\n",
        "        print(\"Error cleaning line: {}\".format(e))\n",
        "        continue\n",
        "\n",
        "      # Write each word in the clean line to the output file\n",
        "      try:\n",
        "        write_words_to_file(cleaned_line, output_file)\n",
        "      except Exception as e:\n",
        "        print(\"Error writing words to file: {}\".format(e))\n",
        "        continue\n",
        "\n",
        "# Open the file and read the text into a variable.\n",
        "try:\n",
        "  with open('moby_01_clean.txt', 'r') as f:\n",
        "    text = f.read()\n",
        "except Exception as e:\n",
        "  raise Exception(\"Error opening file: {}\".format(e))\n",
        "\n",
        "# Split the text into words.\n",
        "try:\n",
        "  words = text.split()\n",
        "except Exception as e:\n",
        "  raise Exception(\"Error splitting text into words: {}\".format(e))\n",
        "\n",
        "# Count the occurrences of each word.\n",
        "try:\n",
        "  word_counts = count_word_occurrences(words)\n",
        "except Exception as e:\n",
        "  raise Exception(\"Error counting word occurrences: {}\".format(e))\n",
        "\n",
        "# Find the most and least common words.\n",
        "try:\n",
        "  most_common, least_common = find_most_and_least_common_words(word_counts)\n",
        "except Exception as e:\n",
        "  raise Exception(\"Error finding most and least common words: {}\".format(e))\n",
        "\n",
        "# Print the results.\n",
        "print(\"Most common words:\")\n",
        "for word, count in most_common:\n",
        "  print(f\"{word}: {count}\")\n",
        "\n",
        "print(\"\\nLeast common words:\")\n",
        "for word, count in least_common:\n",
        "  print(f\"{word}: {count}\")\n",
        "\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "rZXIuSa4d-c5",
        "outputId": "10ef9a1c-b601-46ad-b366-a2652ffee0f8"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Most common words:\n",
            "the: 14\n",
            "and: 9\n",
            "i: 9\n",
            "of: 8\n",
            "is: 7\n",
            "\n",
            "Least common words:\n",
            "call: 1\n",
            "ishmael: 1\n",
            "years: 1\n",
            "ago: 1\n",
            "never: 1\n"
          ]
        }
      ]
    }
  ]
}